package org.example;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 本例 演示如何获取解析方法参数上的注解
 * public void exampleMethod(
             @ ParamInfo("scyParam1") String param1,
             @ ParamInfo("scyParam2") int param2);

 * 在java8之前,方法中参数名是获取不到的,都变成arg0,arg1,可以通过在参数前添加注解
 * 通过获取注解中的值,间接知道是哪个参数
 *
 * 在java8及后续版本中,我们可以通过控制 javac -parameters来保留参数名
 */
public class AppMethodParamAnnoParse {

    static List<String> paraAnnoValues = new ArrayList<>();
    static List<Object> argValues = new ArrayList<>();
    private static Map<String, Object> map = new HashMap<>();


    public static void main(String[] args) throws Exception {
        String clazzName = "org.example.IExample";
        String methodName = "exampleMethod";
        Class<?> aClass = Class.forName(clazzName);

        //第一步:解析class中方法中参数的注解
        parseMethodParamAnnos(aClass, methodName);

        System.out.println("----------------------------------------------------------------");
        System.out.println();
        System.out.println("类" + clazzName + "#" + methodName + "方法中所有参数的注解为:" + paraAnnoValues);
        System.out.println();

        //第二步:调用实现类(一般由框架生成)中的方法
        IExample exampleClass = new IExampleImpl();
        ArrayList<String> friends = new ArrayList<>();
        friends.add("张三");
        friends.add("李四");
        friends.add("王五");
        exampleClass.exampleMethod("时春跃", 22, friends);

        //第三步:将将注解值和参数映射起来
        mapAnnoArgValue();

        System.out.println("得到的所有映射关系是:"+map);
        System.out.println();

        //第四步:分别通过index和key名来获取值
        int index = 2;
        System.out.print("获取index为" + index + "的解析结果是:");
        System.out.println(map.get(paraAnnoValues.get(index)));

        String key = "scyParam2";
        System.out.println("获取"+key+"的值为:"+map.get(key));

    }

    public static void mapAnnoArgValue() {
        for (int i = 0; i < paraAnnoValues.size(); i++) {
            map.put(paraAnnoValues.get(i), argValues.get(i));
        }
    }

    /**
     * 解析一个类中某个方法中参数中的注解
     *
     * @param clazz      需要解析的类
     * @param methodName 需要解析的方法名
     */
    public static void parseMethodParamAnnos(Class<?> clazz, String methodName) {
        try {
            Method method = clazz.getMethod(methodName, new Class[]{String.class, int.class, List.class});
            Parameter[] parameters = method.getParameters();

            for (Parameter parameter : parameters) {
                Annotation[] annotations = parameter.getAnnotations();
                //参数名Parameter: arg0
                System.out.println("参数名Parameter: " + parameter.getName());
                for (Annotation annotation : annotations) {
                    if (annotation instanceof ParamInfo) {
                        ParamInfo paramInfo = (ParamInfo) annotation;
                        //注解的类:org.example.ParamInfo-----注解的parmValue值:scyParam1
                        System.out.println("注解的类:" + paramInfo.annotationType().getName() + "-----注解的parmValue值:" + paramInfo.parmValue());
                        paraAnnoValues.add(paramInfo.parmValue());
                        System.out.println();
                    }
                }
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}